#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/fcntl.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include <string.h>
#include <arpa/inet.h>
#include <linux/if.h>
#include <linux/if_tun.h>
#include <assert.h>
#include <pthread.h>

#include "defs.h"
#include "task.h"
#include "tools.h"

#define MYPORT 5678

struct IPADDR ipaddr[128];

int v6sockfd, tun, max_fd;
char tun_name[IFNAMSIZ];
uinfoptr utable_he;
fd_set in_set;

const char gu_route[] = "0.0.0.0";
char gu_dns[3][32];

void ready_work();

int main(int argc, char * argv[])
{
    ready_work();
    pthread_t pt1, pt2;
    if (pthread_create(&pt1, NULL, keep_live, NULL))
    {
        perror("keeplive thread create");
        exit(errno);
    }
    if (pthread_create(&pt2, NULL, read_tun, NULL))
    {
        perror("read tun thread create");
        exit(errno);
    }
    msg_loop();
    return 0;
}

int tun_create(char *dev, int flags)
{
    struct ifreq ifr;
    int fd, err;

    assert(dev != NULL);

    if ((fd = open("/dev/net/tun", O_RDWR)) < 0)
        return fd;

    memset(&ifr, 0, sizeof(ifr));
    ifr.ifr_flags |= flags;
    if (*dev != '\0')
        strncpy(ifr.ifr_name, dev, IFNAMSIZ);
    if ((err = ioctl(fd, TUNSETIFF, (void *)&ifr)) < 0) {
        close(fd);
        return err;
    }
    strcpy(dev, ifr.ifr_name);

    return fd;
}

void ready_work()
{
    v6sockfd = socket(AF_INET6, SOCK_STREAM, 0);
    if (v6sockfd < 0)
    {
        perror("v6socket create");
        exit(errno);
    }
    printf("v6fd: %d\n", v6sockfd);
    struct sockaddr_in6 my_addr;
    bzero(&my_addr, sizeof(my_addr));
    my_addr.sin6_family = AF_INET6;
    my_addr.sin6_port = htons(MYPORT);
    my_addr.sin6_addr = in6addr_any;
    printf("port: %u\n", ntohs(my_addr.sin6_port));
    if (bind(v6sockfd, (struct sockaddr *)&my_addr,
                sizeof(struct sockaddr_in6)) < 0)
    {
        perror("ready bind1");
        exit(errno);
    }
    if (listen(v6sockfd, 5) < 0)
    {
        perror("ready listen");
        exit(errno);
    }
    // 把该套接字加入Select模型字符集
    max_fd = v6sockfd;
    FD_ZERO(&in_set);
    FD_SET(v6sockfd, &in_set);
    // tun虚接口
    tun_name[0] = '\0';
    if ((tun = tun_create(tun_name, IFF_TUN | IFF_NO_PI)) < 0)
    {
        perror("tun create");
        exit(errno);
    }
    printf("TUN name: %s , fd: %d\n", tun_name, tun);
    // 创建客户信息表和地址池
    memset(ipaddr, 0, sizeof(ipaddr));
    utable_he = NULL;
    ipaddr[0].status = 1;
    const char addr0[] = "13.8.0.1";
    strcpy(ipaddr[0].addr, addr0);
    // 获取服务器DNS地址
    /*system("cat /etc/resolv.conf | grep -i nameserver | cut -c 12-30 > dns.txt");
    FILE * dns_f = fopen("dns.txt", "r");
    fscanf(dns_f, "%s", gu_dns[0]);
    fclose(dns_f);*/
    sprintf(gu_dns[0], "119.29.29.29");
    sprintf(gu_dns[1], "8.8.8.8");
    sprintf(gu_dns[2], "180.76.76.76");
    printf("route & dns: %s %s %s %s\n", gu_route,
            gu_dns[0], gu_dns[1], gu_dns[2]);
    printf("MSGLENGTH:%d\n", MSGLENGTH);
}
